package com.acme.bankapp.domain.bank;

import com.acme.bankapp.exceptions.*;

/**
 * This abstract class implements Account interface
 * 
 * @author Anton Kotov
 * 
 */
@SuppressWarnings("serial")
public abstract class AbstractAccount implements Account {

    @Override
    public int hashCode() {
	final int prime = 31;
	int result = 1;
	long temp;
	temp = Double.doubleToLongBits(balance);
	result = prime * result + (int) (temp ^ (temp >>> 32));
	result = prime * result + id;
	return result;
    }

    @Override
    public boolean equals(Object obj) {
	if (this == obj) {
	    return true;
	}
	if (obj == null) {
	    return false;
	}
	if (!(obj instanceof AbstractAccount)) {
	    return false;
	}
	AbstractAccount other = (AbstractAccount) obj;
	if (Double.doubleToLongBits(balance) != Double
		.doubleToLongBits(other.balance)) {
	    return false;
	}
	if (id != other.id) {
	    return false;
	}
	return true;
    }

    protected int id;
    protected double balance;

    public AbstractAccount(final int id, final double balance) {
	this.id = id;
	this.balance = balance;
    }

    public double getBalance() {
	return balance;
    }

    public void deposit(final double amount) {
	if (amount <= 0.) {
	    throw new IllegalArgumentException();
	}

	balance += amount;
    }

    public void withdraw(final double amount) throws NotEnoughFundsException {
	if (amount <= 0.) {
	    throw new IllegalArgumentException();
	}
	double maximumAmountToWithdraw = maximumAmountToWithdraw();
	if (amount > maximumAmountToWithdraw) {
	    throw new NotEnoughFundsException("Failed to withdraw: "
		    + "trying to withdraw " + amount
		    + " funds. The maximum allowable value is "
		    + maximumAmountToWithdraw);
	}

	balance -= amount;
    }

    @Override
    public String toString() {
	return "Account [id=" + id + ", balance=" + balance + "]";
    }

    @Override
    public long decimalValue() {
	return Math.round(balance);
    }
}
